package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zmj.sy.mom.srv.aps.bean.bo.*;
import com.zmj.sy.mom.srv.aps.bean.bo.plan.PlanFactoryCache;
import com.zmj.sy.mom.srv.aps.bean.bo.plan.PlanOrderCache;
import com.zmj.sy.mom.srv.aps.bean.entity.base.BaseEntity;
import com.zmj.sy.mom.srv.aps.bean.entity.order.*;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.*;
import com.zmj.sy.mom.srv.aps.bean.vo.plan.PlanSchedulingReqVo;
import com.zmj.sy.mom.srv.aps.config.ProjectConfig;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;


@Slf4j
@RequiredArgsConstructor
@Service
public class PlanMbdService {


    private final OrderMapper orderMapper;
    private final ApsOrderMapper apsOrderMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final ApsBatchMapper apsBatchMapper;
    private final ApsWorkOrderMapper apsWorkOrderMapper;
    private final ApsWorkDetailMapper apsWorkDetailMapper;
    private final ApsDetailWeekdayMapper apsDetailWeekdayMapper;

    private final ProjectConfig projectConfig;
    private final CustomerMapper customerMapper;
    private final OrderPhaseMapper orderPhaseMapper;
    private final GroupMapper groupMapper;
//    private final StationGroupMapper stationGroupMapper;
    private final StationMapper stationMapper;
    private final ShiftTypeMapper shiftTypeMapper;
    private final ShiftMapper shiftMapper;
    private final WeekdayRuleMapper weekdayRuleMapper;
    private final BreakPeriodMapper breakPeriodMapper;
    private final PhaseMapper phaseMapper;
    private final OrderBomMapper orderBomMapper;
    private final ReverseDetailMapper reverseDetailMapper;

    public void scheduling(PlanSchedulingReqVo reqVo) {
        log.info("scheduling reqVo: {}", JsonUtils.toJsonString(reqVo));

        PlanOrderCache orderCache = new PlanOrderCache();
        PlanFactoryCache factoryCache = new PlanFactoryCache();

        orderCache.setSchedulingSource("mbd");
        PlanSchedulingReqVo reqVo1 = new PlanSchedulingReqVo();
        initOrderAndApsOrder(reqVo1, orderCache);

        valid(orderCache);

        lock(orderCache);

        clear(orderCache);

        initFactoryCache(factoryCache, orderCache, reqVo);

        initOrderCache(factoryCache, orderCache);

        scheduleTask(factoryCache, orderCache);
//
//        saveAndUpateMbd(orderCache);

    }

    private void saveAndUpateMbd(PlanOrderCache orderCache) {

        // 保存所有的workOrder
        List<ApsWorkOrderTemp> collect = orderCache.getApsWorkOrderTempList().stream().filter(e -> e.getPid() == null).collect(Collectors.toList());
        Map<Integer, ApsWorkOrderTemp> apsWorkOrderTempIdMap = orderCache.getApsWorkOrderTempIdMap();
        Map<Integer, List<ApsWorkOrderTemp>> apsWorkOrderTempPidMap = orderCache.getApsWorkOrderTempPidMap();

        List<ApsWorkOrderTemp> children = new ArrayList<>(collect);
        while (CollUtil.isNotEmpty(children)) {
            List<ApsWorkOrder> saveBatch = children.stream()
                    .map(e -> {
                        if (e.getPid() != null) {
                            e.getApsWorkOrder().setPid(apsWorkOrderTempIdMap.get(e.getPid()).getApsWorkOrder().getId());
                        }
                        e.getApsWorkOrder().setStatus(2);
                        return e.getApsWorkOrder();
                    })
                    .collect(Collectors.toList());
            apsWorkOrderMapper.insertBatch(saveBatch, 1000);

            List<ApsWorkOrderTemp> temp = new ArrayList<>();

            for (ApsWorkOrderTemp child : children) {
                List<ApsWorkOrderTemp> apsWorkOrderTemps = apsWorkOrderTempPidMap.get(child.getId());
                if (CollUtil.isNotEmpty(apsWorkOrderTemps)) {
                    temp.addAll(apsWorkOrderTemps);
                }
            }

            children = temp;
        }

        // 保存所有的workDetail
        for (ApsTask task : orderCache.getTaskList()) {
            ApsWorkOrderTemp apsWorkOrderTemp = apsWorkOrderTempIdMap.get(task.getApsWorkOrderId());
            task.getApsWorkDetailTemp().getApsWorkDetail().setApsWorkOrderId(apsWorkOrderTemp.getApsWorkOrder().getId());
            task.getApsWorkDetailTemp().getApsWorkDetail().setApsWorkOrderPid(apsWorkOrderTemp.getApsWorkOrder().getPid());
            task.getApsWorkDetail().setStatus(2);
        }
        List<ApsWorkDetail> apsWorkDetailList = orderCache.getTaskList().stream().map(ApsTask::getApsWorkDetail).collect(Collectors.toList());
        apsWorkDetailMapper.insertBatch(apsWorkDetailList, 2000);


        // 保存所有的apsDetailWeekday
        for (ApsTask task : orderCache.getTaskList()) {
            for (ApsWeekDayWrap apsWeekDayWrap : task.getAll()) {
                apsWeekDayWrap.setApsWorkOrderId(task.getApsWorkDetail().getApsWorkOrderId());
                apsWeekDayWrap.setApsWorkDetailId(task.getApsWorkDetail().getId());
            }
        }
        List<ApsDetailWeekday> apsDetailWeekdayList = orderCache.getTaskList()
                .stream()
                .flatMap(e -> e.getAll().stream().map(machineCalendar -> {
                    ApsDetailWeekday calendar = new ApsDetailWeekday();

                    calendar.setOrderId(e.getApsWorkDetail().getOrderId());
                    calendar.setApsOrderId(e.getApsWorkDetail().getApsOrderId());
                    calendar.setApsBomId(e.getApsWorkDetail().getApsWorkOrderId());
                    calendar.setPhaseId(e.getApsWorkDetail().getPhaseId());
                    calendar.setPhaseCode(e.getApsWorkDetail().getPhaseCode());
                    calendar.setPhaseName(e.getApsWorkDetail().getPhaseName());
                    calendar.setApsWorkOrderId(e.getApsWorkDetail().getApsWorkOrderId());
                    calendar.setApsWorkDetailId(e.getApsWorkDetail().getId());
                    calendar.setGroupId(e.getApsWorkDetail().getGroupId());

                    calendar.setWorkTime(machineCalendar.getSecond());
                    calendar.setPlanStartDateTime(machineCalendar.getStart());
                    calendar.setPlanEndDateTime(machineCalendar.getEnd());
                    calendar.setShiftId(machineCalendar.getShiftId());
                    calendar.setShiftSeq(machineCalendar.getShiftSeq());
                    calendar.setShiftStartDateTime(machineCalendar.getShiftStartDateTime());
                    calendar.setShiftEndDateTime(machineCalendar.getShiftEndDateTime());
                    calendar.setShiftDay(machineCalendar.getShiftDay());
                    calendar.setStationGroupId(e.getApsWorkDetail().getStationGroupId());
                    calendar.setStationId(e.getApsWorkDetail().getStationId());
                    calendar.setState(2); // 3 已排产
                    calendar.setOrderType(orderCache.getOrderIdMap().get(e.getApsWorkOrder().getOrderId()).getOrderType());
                    return calendar;
                }))
                .collect(Collectors.toList());
        apsDetailWeekdayMapper.insertBatch(apsDetailWeekdayList, 2000);

        Map<Integer, List<ApsWorkOrderTemp>> collect1 = orderCache.getApsWorkOrderTempList().stream().collect(Collectors.groupingBy(e -> e.getApsWorkOrder().getApsOrderId()));
        // 更新 apsOrder
        for (ApsOrder apsOrder : orderCache.getApsOrderList()) {
            List<ApsWorkOrderTemp> apsWorkOrderTemps = collect1.get(apsOrder.getId());
            ApsWorkOrderTemp min = apsWorkOrderTemps.stream().min(Comparator.comparing(e -> e.getApsWorkOrder().getPlanStartDateTime())).get();
            ApsWorkOrderTemp max = apsWorkOrderTemps.stream().max(Comparator.comparing(e -> e.getApsWorkOrder().getPlanEndDateTime())).get();
            apsOrder.setOrderStatus(5);
            apsOrder.setPlanStartDateTime(min.getApsWorkOrder().getPlanStartDateTime());
            apsOrder.setPlanEndDateTime(max.getApsWorkOrder().getPlanEndDateTime());
            apsOrder.setOrderStatus(6);
            apsOrder.setLocked(2);
        }
        apsOrderMapper.updateBatchById(orderCache.getApsOrderList(), 500);

        // 更新 order
        for (Order order : orderCache.getOrderList()) {
            List<ApsOrder> apsOrders = orderCache.getApsOrderOrderIdMap().get(order.getId());
            ApsOrder min = apsOrders.stream().min(Comparator.comparing(ApsOrder::getPlanStartDateTime)).get();
            ApsOrder max = apsOrders.stream().min(Comparator.comparing(ApsOrder::getPlanEndDateTime)).get();
            order.setPlanStartDateTime(min.getPlanStartDateTime());
            order.setPlanEndDateTime(max.getPlanEndDateTime());
            order.setOrderStatus(6);
            order.setPushStatus(1);
            order.setLocked(2);
        }
        orderMapper.updateBatchById(orderCache.getOrderList(), 100);

        orderCache.getApsBatch().setStatus(2);
        apsBatchMapper.updateById(orderCache.getApsBatch());
    }

    public void scheduleTask(PlanFactoryCache factoryCache, PlanOrderCache orderCache) {

        // 找到需要排产的包
        List<ApsOrder> apsOrderList = orderCache.getApsOrderIdMap()
                .values()
                .stream()
                .sorted((e1, e2) -> {

                    int cmp = 0;
                    // 一个批次订单的顺序
                    cmp = orderCache.getOrderIdMap().get(e1.getOrderId()).getSeq().compareTo(orderCache.getOrderIdMap().get(e2.getOrderId()).getSeq());
                    if (cmp != 0) {
                        return cmp;
                    }

                    // 相同批次对比包顺序
                    cmp = e1.getSeq().compareTo(e2.getSeq());
                    if (cmp != 0) {
                        return -cmp;
                    }
                    return cmp;
                })
                .collect(Collectors.toList());

        // 排产每个包
        Map<Integer, List<ApsWorkOrderTemp>> apsWorkOrderApsOrderMap = orderCache.getApsWorkOrderTempList().stream().collect(Collectors.groupingBy(e -> e.getApsWorkOrder().getApsOrderId()));
        Map<Integer, Map<Integer, List<ApsWorkOrderTemp>>> workOrderApsOrderIdPidMap = orderCache.getApsWorkOrderTempList().stream().filter(e -> e.getPid() != null).collect(Collectors.groupingBy(e -> e.getApsWorkOrder().getApsOrderId(), Collectors.groupingBy(ApsWorkOrderTemp::getPid)));
        Map<Integer, Map<Integer, Map<Integer, List<ApsTask>>>> apsTaskWorkOrderIdPhaseSeqMap = orderCache.getTaskList().stream().collect(Collectors.groupingBy(e -> e.getApsWorkOrder().getApsOrderId(), Collectors.groupingBy(e -> e.getApsWorkDetail().getApsWorkOrderId(), Collectors.groupingBy(e -> e.getApsWorkDetail().getPhaseSeq()))));

        List<String> lines = new ArrayList<>();
        for (ApsOrder apsOrder : apsOrderList) {
            // 循环处理每个包的工单
            List<ApsWorkOrderTemp> apsWorkOrderTemps = apsWorkOrderApsOrderMap.get(apsOrder.getId());
            if (CollUtil.isEmpty(apsWorkOrderTemps)) {
                continue;
            }

            List<ApsWorkOrderTemp> parentWorkOrder = apsWorkOrderTemps.stream().filter(e -> e.getPid() == null).collect(Collectors.toList());

            while (!CollUtil.isEmpty(parentWorkOrder)) {

                List<ApsWorkOrderTemp> temp = new ArrayList<>();

                Map<String, Map<String, Integer>> phaseGroupWorkTimeMap = calcPhaseGroupWorkTimeMap(parentWorkOrder, apsOrder, orderCache, factoryCache, apsTaskWorkOrderIdPhaseSeqMap, lines);


                for (ApsWorkOrderTemp workOrderTemp : parentWorkOrder) {

                    phaseList(workOrderTemp, apsOrder, orderCache, factoryCache, apsTaskWorkOrderIdPhaseSeqMap, lines, phaseGroupWorkTimeMap);

                    List<ApsWorkOrderTemp> children = workOrderApsOrderIdPidMap.get(apsOrder.getId()).get(workOrderTemp.getId());
                    if (CollUtil.isEmpty(children)) {
                        continue;
                    }
                    temp.addAll(children);
                }

                parentWorkOrder = temp;
            }

            for (ApsMachine machine : factoryCache.getMachines()) {
                machine.setNextTask(null);
            }

        }

    }

    public void phaseList(ApsWorkOrderTemp workOrderTemp, ApsOrder apsOrder, PlanOrderCache orderCache, PlanFactoryCache factoryCache, Map<Integer, Map<Integer, Map<Integer, List<ApsTask>>>> apsTaskWorkOrderIdPhaseSeqMap, List<String> lines, Map<String, Map<String, Integer>> phaseGroupWorkTimeMap) {

        Map<Integer, List<ApsTask>> phaseSeqMap = apsTaskWorkOrderIdPhaseSeqMap.get(workOrderTemp.getApsWorkOrder().getApsOrderId()).get(workOrderTemp.getId());

        if (CollUtil.isEmpty(phaseSeqMap) && workOrderTemp.getApsWorkOrder().getWorkChain().equals("WL")) {
            LocalDateTime start = orderCache.getApsWorkOrderTempIdMap().get(workOrderTemp.getPid()).getApsWorkOrder().getPlanStartDateTime();

//            PhaseExt phaseExt = factoryCache.getPhaseExtMap().get("WL");
            Phase phase = factoryCache.getPhaseCodeMap().get("WL");
            if (phase == null) {
                workOrderTemp.getApsWorkOrder().setPlanStartDateTime(start);
                workOrderTemp.getApsWorkOrder().setPlanEndDateTime(start);
            } else {
                workOrderTemp.getApsWorkOrder().setPlanEndDateTime(start);
                workOrderTemp.getApsWorkOrder().setPlanStartDateTime(start.plusSeconds(TaskTimeUtils.calcWlTime(phase)));
            }
            return;
        }


        List<Integer> phaseSeqKey = new ArrayList<>(phaseSeqMap.keySet());
        phaseSeqKey.sort(Comparator.comparingInt(e -> -e));

        for (int i = 0; i < phaseSeqKey.size(); i++) {
            Integer phaseSeq = phaseSeqKey.get(i);
            List<ApsTask> taskList = phaseSeqMap.get(phaseSeq);
            if (i == 0 && workOrderTemp.getApsWorkOrder().getLevel().equals(1)) {
                // 如果没有顶层，则取包的结束时间
                LocalDate deliveryDate = orderCache.getApsOrderIdMap().get(workOrderTemp.getApsWorkOrder().getApsOrderId()).getDeliveryDate();
//                List<ApsMachine> apsMachines = factoryCache.getGroupCodeMachineMap().get(taskList.get(0).getGroupCode());
//                ApsWeekDay apsWeekDay = apsMachines.stream().flatMap(e -> e.getWeekDays().stream()).filter(e -> e.getShiftDay().equals(deliveryDate)).max(Comparator.comparing(ApsWeekDay::getEndDateTime)).get();
                for (int i1 = 0; i1 < taskList.size(); i1++) {
//                    taskList.get(i1).getApsWorkDetail().setPlanEndDateTime(apsWeekDay.getEndDateTime());
                    taskList.get(i1).getApsWorkDetail().setPlanEndDateTime(LocalDateTime.of(deliveryDate, LocalTime.of(0, 0, 0, 0)));
                }

            } else if (i == 0 && !workOrderTemp.getApsWorkOrder().getLevel().equals(1)) {
                // 获取顶层的工单时间
                Map<Integer, List<ApsTask>> parentPhaseSeqMap = apsTaskWorkOrderIdPhaseSeqMap.get(workOrderTemp.getApsWorkOrder().getApsOrderId()).get(workOrderTemp.getPid());
                List<ApsTask> parentTaskList = parentPhaseSeqMap.get(new LinkedList<>(parentPhaseSeqMap.keySet()).getFirst());
                int partCount = workOrderTemp.getApsWorkOrder().getPartCount().intValue();
                List<ApsTask> collect = parentTaskList.stream()
                        .sorted(Comparator.comparing((ApsTask e) -> e.getApsWorkDetail().getPlanStartDateTime()).reversed())
                        .flatMap(e -> Stream.iterate(e, e1 -> e1).limit(partCount))
                        .collect(Collectors.toList());

                int last = 0;
                for (ApsTask task : taskList) {
                    BigDecimal totalCount = task.getApsWorkDetail().getTotalCount();
                    Optional<LocalDateTime> min = collect.stream().map(e -> e.getApsWorkDetail().getPlanStartDateTime()).skip(last).limit(totalCount.intValue()).min(Comparator.comparing(e -> e));
                    if (min.isPresent()) {
                        task.getApsWorkDetail().setPlanEndDateTime(min.get());
                        last += totalCount.intValue();
                    }

                }

            } else {
                // 获取前一道工序的时间
                List<ApsTask> preTask = phaseSeqMap.get(phaseSeqKey.get(i - 1));
                ApsTask apsTask = preTask.stream().min(Comparator.comparing((ApsTask e) -> e.getApsWorkDetail().getPlanStartDateTime())).get();

                for (ApsTask task : taskList) {
                    task.getApsWorkDetail().setPlanEndDateTime(apsTask.getPlanStartDateTime());
                }

            }

            List<ApsMachine> machines = factoryCache.getGroupCodeMachineMap().get(taskList.get(0).getGroupCode());
            if (CollUtil.isEmpty(machines)) {
                throw SyExceptionUtils.e("没有找到工作组:[" + factoryCache.getGroupCodeMachineMap().get(taskList.get(0).getGroupCode() + "], 对应的工序:[" + factoryCache.getGroupCodeMachineMap().get(taskList.get(0).getPhaseCode() + "]")));
            }

            for (ApsTask currentTask : taskList) {
                List<ApsDetailWeekdayWrap> l = new ArrayList<>();
                LocalDateTime start = currentTask.getApsWorkDetail().getPlanEndDateTime();
                currentTask.getApsWorkDetail().setPlanEndDateTime(null);

                for (ApsMachine machine : machines) {

                    ApsDetailWeekdayWrap scheduling = PlanTaskUtils.scheduling(factoryCache, orderCache, start, machine, currentTask, apsDetailWeekdayMapper, apsWorkDetailMapper, l, machines, phaseGroupWorkTimeMap);
                    l.add(scheduling);
                }
                ApsDetailWeekdayWrap calendarWrap = l.stream().max(Comparator.comparing(ApsDetailWeekdayWrap::getStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("排产异常"));
                currentTask.getApsWorkDetail().setPlanStartDateTime(calendarWrap.getStartDateTime());
                currentTask.getApsWorkDetail().setPlanEndDateTime(calendarWrap.getEndDateTime());
                currentTask.setNextTask(calendarWrap.getNext());
                calendarWrap.getPrevious().setNextTask(currentTask);
                currentTask.getApsWorkDetail().setStationId(calendarWrap.getMachine().getId());
                currentTask.setStartMachineCalendar(calendarWrap.getStartMachineCalendar());
                currentTask.setAll(calendarWrap.getAll());
                currentTask.getApsWorkDetail().setStatus(2);
                currentTask.setStatus(5);

                calendarWrap.getMachine().setNextTask(null);
            }

        }

        ApsTask minTask = phaseSeqMap.values().stream().flatMap(List::stream).min(Comparator.comparing(ApsTask::getApsWorkDetail, Comparator.comparing(ApsWorkDetail::getPlanStartDateTime))).get();
        ApsTask maxTask = phaseSeqMap.values().stream().flatMap(List::stream).max(Comparator.comparing(ApsTask::getApsWorkDetail, Comparator.comparing(ApsWorkDetail::getPlanEndDateTime))).get();
        workOrderTemp.getApsWorkOrder().setPlanStartDateTime(minTask.getPlanStartDateTime());
        workOrderTemp.getApsWorkOrder().setPlanEndDateTime(maxTask.getPlanEndDateTime());

    }

    public Map<String, Map<String, Integer>> calcPhaseGroupWorkTimeMap(List<ApsWorkOrderTemp> parentWorkOrder, ApsOrder apsOrder, PlanOrderCache orderCache, PlanFactoryCache factoryCache, Map<Integer, Map<Integer, Map<Integer, List<ApsTask>>>> apsTaskWorkOrderIdPhaseSeqMap, List<String> lines) {
        Integer level = parentWorkOrder.get(0).getApsWorkOrder().getLevel();
        List<ApsWorkOrderTemp> collect = parentWorkOrder.stream().filter(e -> e.getApsWorkOrder().getLevel().equals(level)).collect(Collectors.toList());

        Map<String, Map<String, Integer>> phaseGroupWorkTimeMap = new HashMap<>();

        for (ApsWorkOrderTemp apsWorkOrderTemp : collect) {
//            phaseGroupWorkTimeMap.put(apsWorkOrderTemp.getApsWorkOrder().getPhaseCode(), new HashMap<>());

            Map<Integer, List<ApsTask>> phaseSeqMap = apsTaskWorkOrderIdPhaseSeqMap.get(apsWorkOrderTemp.getApsWorkOrder().getApsOrderId()).get(apsWorkOrderTemp.getId());
            if (CollUtil.isEmpty(phaseSeqMap) && apsWorkOrderTemp.getApsWorkOrder().getWorkChain().equals("WL")) {
                continue;
            }
            if (phaseSeqMap == null) {
                throw SyExceptionUtils.e("工单号：{}，PLMID：{}，物料号：{} 没有可执行工序", apsWorkOrderTemp.getApsWorkOrder().getWorkOrderCode(), apsWorkOrderTemp.getApsWorkOrder().getPlmId(), apsWorkOrderTemp.getApsWorkOrder().getPlmId());
            }
            List<Integer> phaseSeqKey = new ArrayList<>(phaseSeqMap.keySet());
            phaseSeqKey.sort(Comparator.comparingInt(e -> -e));

            for (int i = 0; i < phaseSeqKey.size(); i++) {
                Integer phaseSeq = phaseSeqKey.get(i);
                List<ApsTask> taskList = phaseSeqMap.get(phaseSeq).stream().filter(e -> e.getApsWorkOrder().getApsOrderId().equals(apsOrder.getId())).collect(Collectors.toList());

                if (apsWorkOrderTemp.getApsWorkOrder().getMaterType().equals("Assembly")) {

//                    Integer newVal = phaseGroupWorkTimeMap.getOrDefault(taskList.get(0).getPhaseCode(), new HashMap<>())
//                            .compute(taskList.get(0).getGroupCode(), (k, v) -> taskList.get(0).getApsWorkDetail().getWorkTime());
//                            .compute(taskList.get(0).getGroupCode(), (k, v) -> (v == null) ? taskList.get(0).getApsWorkDetail().getWorkTime() : v + taskList.get(0).getApsWorkDetail().getWorkTime());

//                    phaseGroupWorkTimeMap.computeIfAbsent(taskList.get(0).getPhaseCode(), k -> new HashMap<>());
//                    phaseGroupWorkTimeMap.get(taskList.get(0).getPhaseCode()).put(taskList.get(0).getGroupCode(), newVal);

                } else {
                    Integer reduce = taskList.stream()
                            .map(e -> e.getApsWorkDetail().getWorkTime() * e.getApsWorkDetail().getTotalCount().intValue())
                            .reduce(Integer::sum)
                            .get();

                    Integer newVal = phaseGroupWorkTimeMap.getOrDefault(taskList.get(0).getPhaseCode(), new HashMap<>())
                            .compute(taskList.get(0).getGroupCode(), (k, v) -> (v == null) ? reduce : v + reduce);
                    phaseGroupWorkTimeMap.computeIfAbsent(taskList.get(0).getPhaseCode(), k -> new HashMap<>());
                    phaseGroupWorkTimeMap.get(taskList.get(0).getPhaseCode()).put(taskList.get(0).getGroupCode(), newVal);
                }
            }
        }

        return phaseGroupWorkTimeMap;
    }

    public void initOrderCache(PlanFactoryCache factoryCache, PlanOrderCache orderCache) {

        // 2.准备批次数据
        ApsBatch apsBatch = apsBatchMapper.lambdaQuery().eq(ApsBatch::getStatus, 1).one();
        if (apsBatch == null) {
            apsBatch = genBatch(orderCache);
            apsBatchMapper.insert(apsBatch);
        } else {
            modifyBatch(apsBatch, orderCache);
            apsBatchMapper.updateById(apsBatch);
        }
        orderCache.setApsBatch(apsBatch);

        List<Integer> apsOrderIds = orderCache.getApsOrderList().stream().map(BaseEntity::getId).collect(Collectors.toList());
        apsOrderMapper.lambdaUpdate()
                .set(ApsOrder::getOrderStatus, 4)
                .in(ApsOrder::getId, apsOrderIds)
                .update();

        // 初始化排产批次信息
        LocalDateTime now = LocalDateTime.now();
        orderCache.getApsBatch().setStatus(1);
        orderCache.getApsBatch().setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
        orderCache.getApsBatch().setSchedulingDateTime(now);
        apsBatchMapper.updateById(orderCache.getApsBatch());

        for (Order order : orderCache.getOrderList()) {
            order.setPlanStartDateTime(null);
            order.setPlanEndDateTime(null);
            order.setBatchId(orderCache.getApsBatch().getId());
            orderMapper.updateById(order);
        }

        // 初始化所有订单 BOM 的 List 和 Map
        List<OrderBom> orderBomList = orderBomMapper.lambdaQuery().in(OrderBom::getOrderId, orderCache.getOrderIdMap().keySet()).list();
        orderCache.setOrderBomList(orderBomList);

        Map<Integer, List<OrderBom>> orderBomOrderIdMap = orderBomList.stream().collect(Collectors.groupingBy(OrderBom::getOrderId));
        orderCache.setOrderBomOrderIdMap(orderBomOrderIdMap);

        Map<Integer, OrderBom> orderBomIdMap = orderBomList.stream().collect(Collectors.toMap(OrderBom::getId, Function.identity()));
        orderCache.setOrderBomIdMap(orderBomIdMap);

        // 初始化所有订单 PHASE 的 List 和 Map
        List<OrderPhase> orderPhaseList = orderPhaseMapper.lambdaQuery().in(OrderPhase::getOrderId, orderCache.getOrderIdMap().keySet()).list();
        orderCache.setOrderPhaseList(orderPhaseList);

        Map<Integer, List<OrderPhase>> orderPhaseOrderIdMap = orderPhaseList.stream().collect(Collectors.groupingBy(OrderPhase::getOrderId));
        orderCache.setOrderPhaseOrderIdMap(orderPhaseOrderIdMap);

        Map<Integer, OrderPhase> orderPhaseIdMap = orderPhaseList.stream().collect(Collectors.toMap(OrderPhase::getId, Function.identity()));
        orderCache.setOrderPhaseIdMap(orderPhaseIdMap);

        // 初始化所有包的 ApsWorkOrder
        Map<Integer, List<ApsOrder>> apsOrderOrderIdMap = orderCache.getApsOrderOrderIdMap();
        List<ApsWorkOrder> apsWorkOrderList = orderCache.getOrderBomList()
                .stream()
                .map(e -> {
                    ApsWorkOrder apsBom = MkBeanUtils.copyProperties(e, ApsWorkOrder.class);
                    apsBom.setBomId(e.getId());
                    apsBom.setBomPid(e.getPid());
                    apsBom.setId(null);
                    apsBom.setPid(null);
                    apsBom.setStatus(1);
                    apsBom.setFinishCount(new BigDecimal(0));
                    apsBom.setTotalCount(e.getTotalCount());
                    apsBom.setOrderType(orderCache.getOrderIdMap().get(e.getOrderId()).getOrderType());
                    apsBom.setPlmId(e.getPlmId());
//                    apsBom.setApsOrderId(apsOrder.getId());
//                    apsBom.setOrderCount(e.getTotalCount().multiply(new BigDecimal(apsOrder.getOrderQty())));
                    return apsBom;
                })
                .flatMap(e ->
                        apsOrderOrderIdMap.get(e.getOrderId())
                                .stream()
                                .map(e1 -> {
                                    ApsWorkOrder awo = new ApsWorkOrder();
                                    BeanUtils.copyProperties(e, awo);
                                    awo.setApsOrderId(e1.getId());
                                    awo.setOrderCount(e.getTotalCount().multiply(new BigDecimal(e1.getOrderQty())));
                                    return awo;
                                })
                )
//                .filter(e -> !(e.getErpCode().startsWith("010") || e.getErpCode().startsWith("020") || e.getErpCode().startsWith("050")))
                .collect(Collectors.toList());


        // 构建 ApsWorkOrder 缓存对象
        List<ApsWorkOrderTemp> apsWorkOrderTempList = apsWorkOrderList.stream()
                .map(e -> {
                    ApsWorkOrderTemp apsWorkOrderTemp = new ApsWorkOrderTemp();
                    apsWorkOrderTemp.setApsWorkOrder(e);
                    return apsWorkOrderTemp;
                })
                .collect(Collectors.toList());

        Map<Integer, Map<Integer, List<ApsWorkOrderTemp>>> pidBomMap = apsWorkOrderTempList.stream()
                .filter(e -> e.getApsWorkOrder().getBomPid() != null)
                .collect(Collectors.groupingBy(e -> e.getApsWorkOrder().getApsOrderId(), Collectors.groupingBy(e -> e.getApsWorkOrder().getBomPid())));
        List<ApsWorkOrderTemp> parentBoms = apsWorkOrderTempList.stream().filter(e -> e.getApsWorkOrder().getBomPid() == null).collect(Collectors.toList());
        int workOrderId = 1;
        if (CollUtil.isNotEmpty(parentBoms)) {
            for (ApsWorkOrderTemp parentBom : parentBoms) {
                parentBom.setId(workOrderId++);
            }
        }
        while (CollUtil.isNotEmpty(parentBoms)) {

            List<ApsWorkOrderTemp> temp = new ArrayList<>();
            for (ApsWorkOrderTemp parentBom : parentBoms) {
                List<ApsWorkOrderTemp> apsBomChildren = pidBomMap.get(parentBom.getApsWorkOrder().getApsOrderId()).get(parentBom.getApsWorkOrder().getBomId());
                if (CollUtil.isEmpty(apsBomChildren)) {
                    continue;
                }

                if (parentBom.getApsWorkOrder().getWorkChain().equals("WL")) {
                    continue;
                }


                for (ApsWorkOrderTemp apsBom : apsBomChildren) {
                    apsBom.setPid(parentBom.getId());
                }
                temp.addAll(apsBomChildren);

            }

            parentBoms = temp;
            if (CollUtil.isNotEmpty(temp)) {
                for (ApsWorkOrderTemp apsWorkOrderTemp : temp) {
                    apsWorkOrderTemp.setId(workOrderId++);
                }
            }
        }

        apsWorkOrderTempList.removeIf(e -> e.getId() == null);
        orderCache.setApsWorkOrderTempList(apsWorkOrderTempList);
        orderCache.setApsWorkOrderTempIdMap(orderCache.getApsWorkOrderTempList().stream().collect(Collectors.toMap(ApsWorkOrderTemp::getId, Function.identity())));
        orderCache.setApsWorkOrderTempPidMap(orderCache.getApsWorkOrderTempList().stream().filter(e -> e.getPid() != null).collect(Collectors.groupingBy(ApsWorkOrderTemp::getPid, Collectors.toList())));

        // 取出倒排表数据
        List<ReverseDetail> reverseDetails = reverseDetailMapper.lambdaQuery().in(ReverseDetail::getOrderId, orderCache.getOrderIdMap().keySet()).list();
        Map<String, ReverseDetail> collect1 = reverseDetails.stream().collect(Collectors.toMap(e -> e.getOrderId() + ":" + e.getBomId() + ":" + e.getPhaseId(), Function.identity(), (e1, e2) -> e1.getReverseEndTime().isBefore(e2.getReverseEndTime()) ? e1 : e2));
        reverseDetails = collect1.values().stream().sorted(Comparator.comparing(ReverseDetail::getReverseEndTime).thenComparing(ReverseDetail::getPhaseId)).collect(Collectors.toList());
        Map<Integer, List<ReverseDetail>> reverseDetailIdMap = reverseDetails.stream().collect(Collectors.groupingBy(ReverseDetail::getOrderId));
        Map<Integer, Map<Integer, ReverseDetail>> collect = reverseDetails.stream().collect(Collectors.groupingBy(ReverseDetail::getOrderId, Collectors.toMap(ReverseDetail::getPhaseId, Function.identity())));

        orderCache.setReverseDetailList(reverseDetails);
        orderCache.setReverseDetailOrderIdMap(reverseDetailIdMap);
        orderCache.setReverseDetailOrderIdPhaseIdMap(collect);

        // 构建 ApsWorkDetail 缓存对象
        Map<Integer, List<ApsWorkOrderTemp>> apsWorkOrderTempBomIdMap = apsWorkOrderTempList.stream().collect(Collectors.groupingBy(e -> e.getApsWorkOrder().getBomId()));

        List<ApsWorkDetailTemp> apsWorkDetailTempList = new ArrayList<>();
        for (int i = 0; i < reverseDetails.size(); i++) {
            ReverseDetail e = reverseDetails.get(i);

            ApsWorkDetail apsWorkDetail = new ApsWorkDetail();
            apsWorkDetail.setOrderId(e.getOrderId());

            OrderPhase orderPhase = orderPhaseIdMap.get(e.getPhaseId());

            if (factoryCache.getIgnorePhaseCode().contains(orderPhase.getPhaseCode())) {
                continue;
            }

            apsWorkDetail.setPhaseId(orderPhase.getId());
            apsWorkDetail.setWorkTime(orderPhase.getWorkTime());

            apsWorkDetail.setPhaseSeq(orderPhase.getPhaseSeq());
            apsWorkDetail.setPhaseCode(orderPhase.getPhaseCode());
            apsWorkDetail.setPhaseName(orderPhase.getPhaseName());
            apsWorkDetail.setPhaseCode(orderPhase.getPhaseCode());
            apsWorkDetail.setMaterNo(orderPhase.getMaterNo());
            apsWorkDetail.setMaterName(orderPhase.getMaterName());
            apsWorkDetail.setGroupCode(orderPhase.getWorkGroupNumber());
            apsWorkDetail.setOrderType(orderCache.getOrderIdMap().get(orderPhase.getOrderId()).getOrderType());

            // 从倒排表里取
            apsWorkDetail.setPartCount(orderCache.getOrderBomIdMap().get(e.getBomId()).getPartCount());
            apsWorkDetail.setGroupId(e.getGroupId());
            apsWorkDetail.setProcessCount(new BigDecimal(0));
            apsWorkDetail.setFinishCount(new BigDecimal(0));
            apsWorkDetail.setStatus(1);
            apsWorkDetail.setStationGroupId(e.getStationGroupId());

            apsWorkDetail.setDetailSeq(i + 1);
            apsWorkDetail.setReverseDetailId(e.getId());
            apsWorkDetail.setType(2);
            apsWorkDetail.setOp(orderPhase.getOp());
            apsWorkDetail.setOpCode(orderPhase.getOpCode());


            List<ApsWorkOrderTemp> apsWorkOrders = apsWorkOrderTempBomIdMap.get(orderPhase.getBomId());

            for (int i1 = 0; i1 < apsWorkOrders.size(); i1++) {
                ApsWorkOrderTemp apsWorkOrder = apsWorkOrders.get(i1);
                apsWorkDetail.setPlmId(apsWorkOrder.getApsWorkOrder().getPlmId()); // 注意，此处应该挪上面

                ApsWorkDetail awd = new ApsWorkDetail();
                BeanUtils.copyProperties(apsWorkDetail, awd);

                awd.setApsOrderId(apsWorkOrder.getApsWorkOrder().getApsOrderId());
                awd.setApsWorkOrderId(apsWorkOrder.getId());
                awd.setApsWorkOrderPid(apsWorkOrder.getPid());
                awd.setTotalCount(apsWorkOrder.getApsWorkOrder().getOrderCount());


                // 再计算转运数量
                List<Station> stationList = factoryCache.getMasterStationMap().get(e.getGroupCode());
                if (CollUtil.isEmpty(stationList)) {
                    throw SyExceptionUtils.e("{}没有工位", e.getGroupCode());
                }
                Integer smallTransfer = stationList.get(0).getSmallTransfer();
                if (smallTransfer == null || smallTransfer <= 0) {
                    ApsWorkDetailTemp temp = new ApsWorkDetailTemp();
                    temp.setApsWorkOrderTemp(apsWorkOrder);
                    temp.setApsWorkDetail(awd);
                    temp.setApsWorkOrder(apsWorkOrder.getApsWorkOrder());
                    apsWorkDetailTempList.add(temp);
                    continue;
                }

                int div = apsWorkOrder.getApsWorkOrder().getOrderCount().divide(new BigDecimal(smallTransfer), 0, RoundingMode.DOWN).intValue();

                BigDecimal subtract = apsWorkOrder.getApsWorkOrder().getOrderCount().subtract(new BigDecimal(smallTransfer).multiply(new BigDecimal(div)));

                for (int i2 = 0; i2 < div; i2++) {
                    ApsWorkDetail awd1 = MkBeanUtils.copyProperties(awd, ApsWorkDetail.class);
                    awd1.setTotalCount(new BigDecimal(smallTransfer));

                    ApsWorkDetailTemp temp = new ApsWorkDetailTemp();
                    temp.setApsWorkOrderTemp(apsWorkOrder);
                    temp.setApsWorkDetail(awd1);
                    temp.setApsWorkOrder(apsWorkOrder.getApsWorkOrder());
                    apsWorkDetailTempList.add(temp);
                }

                if (subtract.compareTo(BigDecimal.ZERO) > 0) {
                    ApsWorkDetail awd1 = MkBeanUtils.copyProperties(awd, ApsWorkDetail.class);
                    awd1.setTotalCount(subtract);

                    ApsWorkDetailTemp temp = new ApsWorkDetailTemp();
                    temp.setApsWorkOrderTemp(apsWorkOrder);
                    temp.setApsWorkDetail(awd1);
                    temp.setApsWorkOrder(apsWorkOrder.getApsWorkOrder());
                    apsWorkDetailTempList.add(temp);
                }

            }

        }

        int workDetailId = 1;
        for (ApsWorkDetailTemp apsWorkDetailTemp : apsWorkDetailTempList) {
            apsWorkDetailTemp.setId(workDetailId++);
        }

        List<ApsTask> tasks = apsWorkDetailTempList.stream()
                .map(e -> {
                    ApsTask t = new ApsTask(e.getApsWorkDetail());
                    t.setApsWorkOrderTemp(e.getApsWorkOrderTemp());
                    t.setApsWorkDetailTemp(e);
                    t.setApsWorkOrder(e.getApsWorkOrder());
                    t.setId(e.getApsWorkDetail().getId());
                    t.setConsumerStatus(1);
                    t.setConsumerCount(new BigDecimal(0));
                    t.setStatus(2);
                    return t;
                })
                .sorted(Comparator.comparing(t -> t.getApsWorkDetail().getDetailSeq()))
                .collect(Collectors.toList());
        orderCache.setTaskList(tasks);


        Map<Integer, Map<Integer, List<ApsTask>>> workOrderIdPhaseSeqMap = tasks.stream().collect(Collectors.groupingBy(e -> e.getApsWorkOrderTemp().getId(), Collectors.groupingBy(ApsTask::getPhaseSeq)));
        orderCache.setWorkOrderIdPhaseSeqMap(workOrderIdPhaseSeqMap);

        Map<Integer, List<ApsTask>> workOrderPidMap = tasks.stream().filter(e -> e.getApsWorkOrderPid() != null).collect(Collectors.groupingBy(ApsTask::getApsWorkOrderPid));
        orderCache.setWorkOrderPidMap(workOrderPidMap);

        for (Order order : orderCache.getOrderList()) {
            order.setPlanStartDateTime(null);
            order.setPlanEndDateTime(null);
        }

        for (ApsOrder apsOrder : orderCache.getApsOrderList()) {
            apsOrder.setPlanStartDateTime(null);
            apsOrder.setPlanEndDateTime(null);
        }

    }


    public void initFactoryCache(PlanFactoryCache factoryCache, PlanOrderCache orderCache, PlanSchedulingReqVo reqVo) {

        // 设置工厂信息
        factoryCache.setFactoryCode(projectConfig.getFactoryCode());

        // 设置客户信息
        List<Integer> customerList = orderCache.getApsOrderList().stream().map(ApsOrder::getCustomerId).distinct().collect(Collectors.toList());
        if (CollUtil.isNotEmpty(customerList)) {
            List<Customer> customers = customerMapper.selectBatchIds(customerList);
            factoryCache.setCustomers(customers);
        }

        // 工作组信息
        List<String> groupNumberString = orderPhaseMapper.selectGroupList(Wrappers.<OrderPhase>query()
                .in("order_id", orderCache.getOrderIdMap().keySet())
        );
        List<Group> groups = groupMapper.lambdaQuery().in(Group::getMyCode, groupNumberString).list();
        factoryCache.setGroups(groups);

        // 工作组工位关联
//        List<StationGroup> stationGroups = stationGroupMapper.lambdaQuery().in(StationGroup::getGroupId, groups.stream().map(BaseEntity::getId).collect(Collectors.toList())).list();
//        factoryCache.setStationGroups(stationGroups);

        // 工位信息
//        List<Integer> stationIds = stationGroups.stream().map(StationGroup::getStationId).distinct().collect(Collectors.toList());
//        List<Station> stations = stationMapper.selectBatchIds(stationIds);
        List<Station> stations = stationMapper.lambdaQuery().in(Station::getGroupId, groups.stream().map(BaseEntity::getId).collect(Collectors.toList())).list();
        List<Integer> stationIds = stations.stream().map(Station::getId).distinct().collect(Collectors.toList());

        for (Station station : stations) {
            if (station.getEnterTime() == null || station.getEnterTime() < 0) {
                station.setEnterTime(0);
            }

            if (station.getOutTime() == null || station.getOutTime() < 0) {
                station.setOutTime(0);
            }

            if (station.getChangTime() == null || station.getChangTime() < 0) {
                station.setChangTime(0);
            }
        }

        factoryCache.setStations(stations);

        // 快捷从工作组找到主工位列表
        Map<Integer, List<Station>> stationGroupMap = stations.stream().collect(Collectors.groupingBy(Station::getGroupId));
        Map<Integer, Station> stationMap = stations.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        Map<String, List<Station>> masterStationMap = new HashMap<>();
        for (Group group : groups) {
            List<Station> value = stationGroupMap.get(group.getId());
//            if (CollUtil.isEmpty(stationGroups1)) {
//                continue;
//            }

//            List<Station> value = stationGroupMap.get(group.getId())
//                    .stream()
//                    .map(e -> stationMap.get(e.getStationId()))
//                    .collect(Collectors.toList());

            masterStationMap.put(group.getMyCode(), value);
        }
        factoryCache.setMasterStationMap(masterStationMap);

        // 工位日历
        List<Integer> stationShiftTypeIds = stations.stream().map(Station::getShiftTypeId).distinct().collect(Collectors.toList());
        List<ShiftType> shiftTypes = shiftTypeMapper.selectBatchIds(stationShiftTypeIds);

        List<Integer> shiftTypeIds = shiftTypes.stream().map(ShiftType::getId).distinct().collect(Collectors.toList());
        List<Shift> shifts = shiftMapper.lambdaQuery().in(Shift::getShiftTypeId, shiftTypeIds).list();

        List<WeekdayRule> stationWeekdayRules = weekdayRuleMapper.lambdaQuery().in(WeekdayRule::getShiftTypeId, stationShiftTypeIds).list();

        List<BreakPeriod> breakPeriods = breakPeriodMapper.lambdaQuery().in(BreakPeriod::getShiftId, shifts.stream().map(BaseEntity::getId).distinct().collect(Collectors.toList())).list();
        Map<Integer, Shift> shiftIdMap = shifts.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

//        factoryCache.setStationWeekdaySchemes(stationWeekdaySchemes);
        factoryCache.setStationWeekdayRules(stationWeekdayRules);
        factoryCache.setShiftTypes(shiftTypes);
        factoryCache.setShifts(shifts);
        factoryCache.setBreakPeriods(breakPeriods);

        // 拼装设备时间链 算法diff不同
        LocalDate startDate = reqVo.getStartDate();
        LocalDate endDate = reqVo.getStartDate().plusDays(30);

        // 初始化日历
        factoryCache.setMachines(stations.stream().map(ApsMachine::new).collect(Collectors.toList()));
        factoryCache.initDay(startDate, endDate);
        for (ApsMachine machine : factoryCache.getMachines()) {
            Integer totalWorkTime = machine.getWeekDays()
                    .stream()
                    .map(e -> shiftIdMap.get(e.getShiftId()).getTotalWorkTime())
                    .reduce(0, Integer::sum)
                    .intValue();

            Integer validTime = machine.getWeekDays()
                    .stream()
                    .map(e -> shiftIdMap.get(e.getShiftId()).getValidTime())
                    .reduce(0, Integer::sum)
                    .intValue();

            machine.setTotalWorkTime(totalWorkTime);
            machine.setValidTime(validTime);

        }


        // 生产工单占位填充 未编写,领导要求无限产能

        // 工作组映射关系填充
        Map<String, List<ApsMachine>> groupCodeMachineMap = new HashMap<>();
        Map<Integer, ApsMachine> idApsMachineMap = factoryCache.getMachines().stream().collect(Collectors.toMap(ApsMachine::getId, Function.identity()));
        for (Map.Entry<String, List<Station>> entry : masterStationMap.entrySet()) {
            List<Station> collect = entry.getValue().stream().filter(e -> e.getWorkAbility() == null).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)) {
                throw SyExceptionUtils.e("工位{}没有工作能力", entry.getValue().get(0).getName());
            }

            List<Station> collect1 = entry.getValue().stream().filter(e -> e.getProductivity() == null).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect1)) {
                throw SyExceptionUtils.e("工位{}没有生产效率", entry.getValue().get(0).getName());
            }
            groupCodeMachineMap.put(entry.getKey(), entry.getValue().stream().map(e -> idApsMachineMap.get(e.getId())).collect(Collectors.toList()));
        }

        factoryCache.setGroupCodeMachineMap(groupCodeMachineMap);

        factoryCache.setIgnorePhaseCode(projectConfig.getIgnorePhaseCodeList());

        factoryCache.setPzCode(WorkshopProp.PZ_PHASE_CODE);

        factoryCache.setPzSecond(WorkshopProp.PZ_SECOND);

//        List<PhaseExt> phaseExtList = phaseExtMapper.lambdaQuery().list();
//        factoryCache.setPhaseExtList(phaseExtList);
//        factoryCache.setPhaseExtMap(phaseExtList.stream().collect(Collectors.toMap(PhaseExt::getPhaseCode, Function.identity())));

        List<Phase> phaseList = phaseMapper.lambdaQuery().list();
        Map<String, Phase> phaseCodeMap = phaseList.stream().collect(Collectors.toMap(Phase::getMyCode, Function.identity()));
        factoryCache.setPhaseCodeMap(phaseCodeMap);

    }

    public void clear(PlanOrderCache orderCache) {
        for (Map.Entry<Integer, List<ApsOrder>> entry : orderCache.getApsOrderOrderIdMap().entrySet()) {
            LambdaUpdateWrapper<ApsOrder> wr = Wrappers.lambdaUpdate();
            wr.set(ApsOrder::getPlanStartDateTime, null);
            wr.set(ApsOrder::getPlanEndDateTime, null);
            wr.in(ApsOrder::getId, entry.getValue().stream().map(BaseEntity::getId).collect(Collectors.toList()));
            apsOrderMapper.update(null, wr);

            apsWorkOrderMapper.deleteOrderId(entry.getKey());
            apsWorkDetailMapper.deleteOrderId(entry.getKey());
            apsDetailWeekdayMapper.deleteOrderId(entry.getKey());
        }

    }



    public void lock(PlanOrderCache orderCache) {

        // 1.把待排产的订单号放入redis，设置锁定状态
        ValueOperations<String, String> valOperation = stringRedisTemplate.opsForValue();
        String redisVal = orderCache.getOrderList().stream().map(e -> e.getConstructNo() + "_" + e.getMaterName()).collect(Collectors.joining(","));
        valOperation.set(ApsConstant.APS_SCHEDULING_LOCK, redisVal, 1, TimeUnit.DAYS);

    }

    public void modifyBatch(ApsBatch apsBatch, PlanOrderCache reqVo) {
        LocalDateTime now = LocalDateTime.now();
        apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
        apsBatch.setSchedulingDateTime(now);
        apsBatch.setSchedulingRule(reqVo.getSchedulingRule());
    }

    public ApsBatch genBatch(PlanOrderCache reqVo) {
        LocalDateTime now = LocalDateTime.now();
        ApsBatch apsBatch = new ApsBatch();
        apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
        apsBatch.setSchedulingRule(reqVo.getSchedulingRule());
        apsBatch.setSchedulingDateTime(now);
        apsBatch.setStatus(1);
        return apsBatch;
    }


    public void valid(PlanOrderCache orderCache) {

        // 如果为 3.待排产 4.排产中 5.已排产，则提示报错
        long count = orderCache.getOrderList().stream().filter(e -> e.getOrderStatus() < 3 || e.getOrderStatus() > 5 ).count();
        if (count > 0) {
            throw SyExceptionUtils.e("有排产中的订单，请稍后再试");
        }

        // 取出所有待排产的订单
        if (CollUtil.isEmpty(orderCache.getOrderList())) {
            throw SyExceptionUtils.e("没有待排产的订单");
        }

        // 检查redis是否有锁定状态，如果有则提示，并且不排产
        ValueOperations<String, String> valOperation = stringRedisTemplate.opsForValue();
        String lockFlag = valOperation.get(ApsConstant.APS_SCHEDULING_LOCK);
        if (StringUtils.hasText(lockFlag)) {
            throw SyExceptionUtils.e("{} 等订单排产中!", lockFlag);
        }

    }

    public void initOrderAndApsOrder(PlanSchedulingReqVo reqVo, PlanOrderCache orderCache) {
        // order
        List<Order> orderList = orderMapper.lambdaQuery()
                .in(Order::getOrderType, ApsConstant.ORDER_TYPE_MAP.get(orderCache.getSchedulingSource()))
                .in(Order::getOrderStatus, 3, 4, 5)
                .list();

        if (CollUtil.isEmpty(orderList)) {
            throw SyExceptionUtils.e("没有待排产的订单");
        }

        orderCache.setOrderList(orderList);
        orderCache.setOrderIdMap(orderList.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity())));
        orderCache.setSchedulingRule(reqVo.getSchedulingRule());

        // apsOrder
        List<Integer> orderIds = orderList.stream().map(BaseEntity::getId).collect(Collectors.toList());
        List<ApsOrder> apsOrderList = apsOrderMapper.lambdaQuery()
                .in(ApsOrder::getOrderId, orderIds)
                .in(ApsOrder::getOrderType, ApsConstant.ORDER_TYPE_MAP.get(orderCache.getSchedulingSource()))
                .list();
        orderCache.setApsOrderList(apsOrderList);
        orderCache.setApsOrderIdMap(apsOrderList.stream().collect(Collectors.toMap(ApsOrder::getId, Function.identity())));
        Map<Integer, List<ApsOrder>> orderMap = orderCache.getApsOrderList().stream().sorted(Comparator.comparing(ApsOrder::getSeq)).collect(Collectors.groupingBy(ApsOrder::getOrderId, LinkedHashMap::new, Collectors.toList()));
        orderCache.setApsOrderOrderIdMap(orderMap);

    }



    public void unlock(PlanSchedulingReqVo reqVo) {
        stringRedisTemplate.delete(ApsConstant.APS_SCHEDULING_LOCK);
    }
}
